#ifndef SYSIO_FILEBUF_HH__
#define SYSIO_FILEBUF_HH__

#include <streambuf>
#include <vector>

#include <unistd.h>

namespace ext
{
    template <typename charT, typename Traits = std::char_traits<charT> >
    class sysio_filebuf;

    /**
     * for non-gnu compillers replacement of stdio_filebuf
     */
    template <typename charT, typename Traits>
    class sysio_filebuf: public std::basic_streambuf<charT,Traits>
    {
	typedef Traits				traits_type;
	typedef charT		   		char_type;
	typedef typename traits_type::int_type	int_type;
	typedef std::vector<char_type>		vector_type;
	using std::basic_streambuf<charT,Traits>::gptr;
	using std::basic_streambuf<charT,Traits>::egptr;

	public:
	    sysio_filebuf(int fd, std::ios_base::openmode mode, bool del, 
		    size_t size):
		    fd_(fd),
		    mode_(mode),
		    del_(del),
		    buffer_(size)
	    {
		char_type *ptr = &buffer_[0];
		setg(ptr,
		     ptr+size,
		     ptr+size);
	    }
	    virtual ~sysio_filebuf()
	    {
		if (del_) close(fd_);
	    }
	    int fd() { return fd_; }
	protected:
	    virtual int_type underflow()
	    {
		char_type *ptr = &buffer_[0];
		if (gptr() < egptr())
        	return traits_type::to_int_type(*gptr());
		
		const int size = buffer_.size();
    		const int len = read(fd_, ptr, size*sizeof(char_type));
    		if (len <= 0)
		{
		    setg(ptr,
			 ptr+size,
			 ptr+size);
		    return traits_type::eof();
    		}
	    
		setg(ptr,
	            ptr,
		    ptr+len);

	        return traits_type::to_int_type(*gptr());
	    }
	    
	    virtual int_type overflow (int_type c = traits_type::eof())
	    {
		if (!traits_type::eq_int_type(c,traits_type::eof()))
		{
		    std::vector<char_type> buffer(1);
		    buffer[0]=traits_type::to_char_type(c);
		    if (write (fd_, &buffer[0], sizeof(char_type)) != sizeof(char_type))
            		return traits_type::eof();
		    return c;
		}
		else
		    return traits_type::not_eof(c);
	    }

	    virtual
	    std::streamsize xsputn (const char_type* p,std::streamsize n)
	    {
    		return write(fd_,p,n);
	    }

	private:
		int 			fd_;
		std::ios_base::openmode	mode_;
		bool			del_;
		vector_type		buffer_;
    };
}

#endif
